/*!
 * \file xml_core.h
 *
 * \brief XML模块主文件
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.
 *
 * \version 1.0
 * \author songbb
 * \date 2016/08/08
 *
 */

#ifndef __XML_CORE_H_
#define __XML_CORE_H_

#include "frlist.h"
#include "frhash2.h"
#include "frstr.h"

#include "conntrack.h"
#include "module.h"
#include "frbyte_buffer.h"

#define APM_XML_PKT_HDR_LEN_MAX 12 //!< 通用头最大长度

/*! @brief XML协议通用包头 */
typedef struct __st_xml_header
{
    unsigned int ui_header_len;          /*!< 消息头长度 */
    unsigned int ui_pkt_len;             /*!< 消息体长度 */
} xml_header;

/*! @brief 包头的类型 */
typedef enum __em_xml_hdr_type {
    APM_XML_HDR_TYPE_INIT = 0,
    APM_XML_HDR_TYPE_UNKNOWN,
    APM_XML_HDR_TYPE_ZERO,                    //!< 0个字节,纯XML格式
    APM_XML_HDR_TYPE_4BIN_TOTAL,              //!< 长度字段由4个字节的二进制组成,表示包体长度(包含包头和XML)
    APM_XML_HDR_TYPE_4BIN_XML,                //!< 长度字段由4个字节的二进制组成,表示XML长度
    APM_XML_HDR_TYPE_4ASCII_TOTAL,            //!< 长度字段由4个字节的ASCII码组成,表示包体长度(包含包头和XML)
    APM_XML_HDR_TYPE_4ASCII_XML,              //!< 长度字段由4个字节的ASCII码组成,表示XML长度
    APM_XML_HDR_TYPE_8BIN_TOTAL,              //!< 长度字段由8个字节的二进制组成,表示包体长度(包含包头和XML)
    APM_XML_HDR_TYPE_8BIN_XML,                //!< 长度字段由8个字节的二进制组成,表示XML长度
    APM_XML_HDR_TYPE_8ASCII_TOTAL,            //!< 长度字段由8个字节的ASCII码组成,表示包体长度(包含包头和XML)
    APM_XML_HDR_TYPE_8ASCII_XML,              //!< 长度字段由8个字节的ASCII码组成,表示XML长度
} xml_hdr_type;

/*! @brief L7session_xml 用于存放XML私有的session数据，对应L7_session的p_session_private变量 */
typedef struct __st_L7session_xml
{
    xml_hdr_type hdr_type;                              //!< 通用头类型
    unsigned int ui_hdr_flag_len;                       //!< 通用头长度
    int i_hdrlen_from_head;                             //!< 通用头表示长度的字段在通用头前部位置
} L7session_xml;

/*! @brief 分片的状态 */
typedef enum __em_fragment_state {
    APM_XML_FRAGMENT_INIT,                     //!< 初始化
    APM_XML_FRAGMENT_NEED_NEXT_REQ_PACKET,     //!< 需要下一个请求包
    APM_XML_FRAGMENT_NEED_NEXT_RESP_PACKET     //!< 需要下一个响应包
} xml_fragment_state;

/*! @brief XML数据包 */
typedef struct __st_L7_xml_packet
{
    xml_fragment_state fragment_state;    //!< 当前的分片状态
    Frbyte_Packet *p_st_packet;             //!< 组包完成的数据
    unsigned int ui_header_len;             //!< Header长度
    unsigned int ui_length;                 //!< 数据包长度
    unsigned int ui_len_to_read;            //!< 还需要从下一个payload中读取多少个字节
    struct timeval st_timestamp_first;      //!< 第一个请求的分片包的时间
    struct timeval st_timestamp_last;       //!< 最后一个请求的分片包的时间
    int i_is_req;                           //!< 是否是请求包
} L7_xml_packet;

/*! @brief XML交易信息 */
typedef struct __st_L7_xml_stmt
{
    struct timeval st_req_end_timestamp;    //!< 请求的结束时间戳
    struct timeval st_resp_start_timestamp; //!< 响应的开始时间戳
    unsigned long ul_resp_server_time_us;   //!< 响应的Server时间
} L7_xml_stmt;

/*! @brief XML私有结构体 */
typedef struct __st_L7session_xml_private
{
    L7session_xml *p_st_sess;                 //!< session数据
    L7_xml_stmt *p_st_xml_stmt;             //!< 按message_id建立hash
    L7_xml_packet *p_st_xml_packet;         //!< 当前处理中的xml数据包
    Frlist_header *p_report_comm;               //!< 用于临时存储report的公共部分数据
    Frlist_header *p_report_req;                //!< 用于临时存储report的请求部分数据
    L7_session *p_st_session;                   //!< 指向父级的L7_session结构体
} L7session_xml_private;

/*! @brief 用于存储在detect过程中的中间数据 */
typedef struct __st_xml_detect_session
{
    xml_hdr_type hdr_type;                              //!< 通用头类型
    char arr_hdr[APM_XML_PKT_HDR_LEN_MAX];              //!< 通用头内容
    int i_hdrlen_from_head;                             //!< 通用头表示长度的字段在通用头前部位置
    unsigned int ui_hdr_flag_len;                       //!< 通用头长度
    unsigned int ui_pkt_len;                            //!< 记录当前的包长
    unsigned int ui_dst_ip;                             //!< 当前包的目的IP
    unsigned short us_dst_port;                         //!< 当前包的目的端口
} xml_detect_session;

/*!
 * 判断当前数据链路是否是XML协议的
 *
 * \param p_st_conn        (ct信息)
 * \param p_st_packet      (协议分析入力数据)
 *
 * \return 参照module.h中APM_L7_IS_的定义
 *
 */
int xml_detect(Conntrack *p_st_conn
                , Apm_packet *p_st_packet);

/*!
 * XML协议解析入口
 *
 * \param p_st_conn             (ct信息)
 * \param p_st_packet           (协议分析入力数据)
 * \param p_st_hash_report      (保存Frreport_data)
 *
 * \return 参照module.h中APM_L7_ANALYZE_的定义
 *
 */
int xml_analyze(Conntrack *p_st_conn
                , Apm_packet *p_st_packet
                , Frhash_header *p_st_hash_report);

/*!
 * 释放XML private数据
 *
 * \param p_st_session_private_in        (XML的私有信息)
 *
 * \return 0  失败\n
 *         1  成功
 *
 */
int xml_session_destory(void *p_st_session_private_in);

#endif
